package com.example.demo.aspect;

import com.example.demo.handler.BusinessException;
import com.example.demo.handler.GlobalExceptionHandler;
import com.example.demo.util.JsonUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * 使用Aop进行日志监控打印
 */
@Aspect
@Component
public class LogAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    GlobalExceptionHandler globalExceptionHandler;

    //	定义切面
    @Pointcut("@annotation(com.example.demo.aspect.WebLog)")
    public void webLog() {
    }

    /**
     * 本系统出现异常打印
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //异常日志信息
        String actionLog = null;
        StackTraceElement[] stackTrace = null;
        //计算执行时间
        Long startTime = System.currentTimeMillis();
        Long endTime;
        Long executionTime = 0L;
        OperationLog operationLog;
        boolean isException = false;
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object obj = null;
        try {
            //监控执行的方法
            obj = proceedingJoinPoint.proceed();
            endTime = System.currentTimeMillis();
            executionTime = endTime - startTime;
        } catch (BusinessException e) {
            endTime = System.currentTimeMillis();
            executionTime = endTime - startTime;
            isException = true;
            operationLog = logHandle(proceedingJoinPoint, actionLog, executionTime, isException, stackTrace, request,
                    obj, e.toString());
            logger.info("Business Error:" + operationLog.toString());

            return globalExceptionHandler.handleBusinessException(e);
        } catch (Exception e) {
            endTime = System.currentTimeMillis();
            executionTime = endTime - startTime;
            isException = true;
            operationLog = logHandle(proceedingJoinPoint, actionLog, executionTime, isException, stackTrace, request,
                    obj, e.toString());
            logger.info("Server Error:" + operationLog.toString());
            return globalExceptionHandler.printLog(e);
        }
        operationLog = logHandle(proceedingJoinPoint, actionLog, executionTime, isException, stackTrace, request, obj
                , "");
        logger.info(operationLog.toString());
        return obj;
    }

    private OperationLog logHandle(ProceedingJoinPoint joinPoint, String actionLog, Long spendTime, boolean isException,
                                   StackTraceElement[] stackTrace, HttpServletRequest request, Object obj,
                                   String message) {

        OperationLog operationLog = new OperationLog();
        operationLog.setClassName(joinPoint.getTarget().getClass().getName());
        operationLog.setMethodName(joinPoint.getSignature().getName());
        operationLog.setUrl(request.getRequestURI().toString());
        operationLog.setHttpMethod(request.getMethod().toString());
        operationLog.setIp(request.getRemoteAddr().toString());
        Enumeration<String> enu = request.getParameterNames();
        StringBuilder parms = new StringBuilder(" ");
        while (enu.hasMoreElements()) {
            String name = enu.nextElement();
            parms.append("" + name + ":");
            parms.append(request.getParameter(name) + ",");
        }
        operationLog.setArgs(parms.toString().substring(0, parms.toString().length() - 1));
        operationLog.setReqParams(JsonUtil.toJsonFromBean(joinPoint.getArgs()));
        operationLog.setSpendTime(spendTime);

        operationLog.setSucceed(isException == true ? "ERROR" : "SUCCESS");
        operationLog.setRespParams(JsonUtil.toJsonFromBean(obj));
        if (isException) {
            operationLog.setMessage(message);
        }
        return operationLog;
    }
}
